﻿using dbe.FoundationLibrary.Core.Win32.API;
using dbe.FoundationLibrary.Core.Win32.Structures;

using System;
using System.Text;

namespace dbe.FoundationLibrary.Core.Extensions
{
    /// <summary>
    /// IntPtr的扩展方法
    /// </summary>
    public static class IntPtrExtension
    {
        static readonly _BLENDFUNCTION blendFunction = new _BLENDFUNCTION
        {
            BlendOp = WinGdi.AC_SRC_OVER,
            BlendFlags = 0,
            SourceConstantAlpha = 255, // 255 表示不透明
            AlphaFormat = WinGdi.AC_SRC_ALPHA
        };
        // 创建TRIVERTEX数组
        static readonly _TRIVERTEX[] vertices = new _TRIVERTEX[2];
        // 创建GRADIENT_RECT数组
        static readonly _GRADIENT_RECT[] mesh = new _GRADIENT_RECT[1];

        /// <summary>
        /// 绘制圆
        /// </summary>
        /// <param name="hdc"></param>
        public static void DrawEllipse(this IntPtr hdc, IntPtr hPen, int centerX, int centerY, int radius)
        {
            IntPtr oldPen = Gdi32.SelectObject(hdc, hPen);
            Gdi32.Ellipse(hdc, centerX - radius, centerY - radius, centerX + radius, centerY + radius);
            Gdi32.SelectObject(hdc, oldPen);
        }

        ///<summary>
        /// 直接使用gdi32.dll中的C++函数绘制图像以提高性能
        ///</summary>
        ///<param name="hdc">设备上下文的句柄</param>
        ///<param name="hImage">图像</param>
        ///<param name="width">图像宽</param>
        ///<param name="height">图像高</param>
        ///<param name="panX">X偏移量</param>
        ///<param name="panY">Y偏移量</param>
        ///<param name="zoom">缩放比例</param>
        public static void DrawImage(this IntPtr hdc, IntPtr hImage, int width, int height, int panX, int panY, float zoom)
        {
            Gdi32.SetStretchBltMode(hdc, GDIConst.STRETCH_DELETESCANS);
            IntPtr hMemDC = Gdi32.CreateCompatibleDC(hdc);
            IntPtr hOldBitmap = Gdi32.SelectObject(hMemDC, hImage);
            int w = (int)(width * zoom);
            int h = (int)(height * zoom);
            Gdi32.StretchBlt(hdc, panX, panY, w, h, hMemDC, 0, 0, width, height, GDIConst.SRCCOPY);
            Gdi32.SelectObject(hdc, hMemDC);
            Gdi32.DeleteDC(hOldBitmap);
            Gdi32.DeleteDC(hMemDC);
        }

        /// <summary>
        /// 铺满
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="hImage"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="srcWidth"></param>
        /// <param name="srcHeight"></param>
        /// <param name="destWidth"></param>
        /// <param name="destHeight"></param>
        public static void DrawImage(this IntPtr hdc, IntPtr hImage, int x, int y, int srcWidth, int srcHeight, int destWidth, int destHeight)
        {
            Gdi32.SetStretchBltMode(hdc, GDIConst.STRETCH_DELETESCANS);
            IntPtr hMemDC = Gdi32.CreateCompatibleDC(hdc);
            IntPtr hOldBitmap = Gdi32.SelectObject(hMemDC, hImage);
            Gdi32.StretchBlt(hdc, x, y, destWidth, destHeight, hMemDC, 0, 0, srcWidth, srcHeight, GDIConst.SRCCOPY);
            Gdi32.SelectObject(hdc, hMemDC);
            Gdi32.DeleteDC(hOldBitmap);
            Gdi32.DeleteDC(hMemDC);
        }

        public static void DrawImage(this IntPtr hdc, IntPtr hImage, int width, int height, int destWidth, int destHeight)
        {
            float scaleX = (float)destWidth / width;
            float scaleY = (float)destHeight / height;
            float scale = Math.Min(scaleX, scaleY);
            int w = (int)(width * scale);
            int h = (int)(height * scale);
            int x = (destWidth - w) >> 1;
            int y = (destHeight - h) >> 1;
            DrawImage(hdc, hImage, width, height, x, y, scale);
        }

        /// <summary>
        /// 背景透明
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="hImage"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="srcWidth"></param>
        /// <param name="srcHeight"></param>
        /// <param name="destWidth"></param>
        /// <param name="destHeight"></param>
        public static void DrawImageTransparenc(this IntPtr hdc, IntPtr hImage, int x, int y, int srcWidth, int srcHeight, int destWidth, int destHeight)
        {
            Gdi32.SetStretchBltMode(hdc, GDIConst.STRETCH_DELETESCANS);
            IntPtr hMemDC = Gdi32.CreateCompatibleDC(hdc);
            IntPtr hOldBitmap = Gdi32.SelectObject(hMemDC, hImage);
            MsImg32.AlphaBlend(hdc, x, y, destWidth, destHeight, hMemDC, 0, 0, srcWidth, srcHeight, blendFunction);
            Gdi32.SelectObject(hMemDC, hOldBitmap);
            Gdi32.DeleteDC(hOldBitmap);
            Gdi32.DeleteDC(hMemDC);
        }

        /// <summary>
        /// 绘制线段
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="startX"></param>
        /// <param name="startY"></param>
        /// <param name="endX"></param>
        /// <param name="endY"></param>
        public static void DrawLine(this IntPtr hdc, int startX, int startY, int endX, int endY)
        {
            Gdi32.MoveToEx(hdc, startX, startY, IntPtr.Zero);
            Gdi32.LineTo(hdc, endX, endY);
        }

        /// <summary>
        /// 以制定画笔绘制线段
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="hPen"></param>
        /// <param name="startX"></param>
        /// <param name="startY"></param>
        /// <param name="endX"></param>
        /// <param name="endY"></param>
        public static void DrawLine(this IntPtr hdc, IntPtr hPen, int startX, int startY, int endX, int endY)
        {
            IntPtr oldPen = Gdi32.SelectObject(hdc, hPen);// 将画笔选入设备环境
            DrawLine(hdc, startX, startY, endX, endY);
            Gdi32.SelectObject(hdc, oldPen); // 恢复原来的画笔
        }

        /// <summary>
        /// 绘制仅有边框的矩形
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public static void DrawRectangle(this IntPtr hdc, int x, int y, int width, int height)
        {
            int x1 = x + width;
            int y1 = y + height;
            DrawLine(hdc, x, y, x1, y);
            DrawLine(hdc, x, y, x, y1);
            DrawLine(hdc, x1, y, x1, y1);
            DrawLine(hdc, x, y1, x1, y1);
        }

        /// <summary>
        /// 以制定画笔绘制矩形
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="hPen"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public static void DrawRectangle(this IntPtr hdc, IntPtr hPen, int x, int y, int width, int height)
        {
            IntPtr oldPen = Gdi32.SelectObject(hdc, hPen);// 将画笔选入设备环境
            DrawRectangle(hdc, x, y, width, height);
            Gdi32.SelectObject(hdc, oldPen); // 恢复原来的画笔
        }

        /// <summary>
        /// 以指定字体绘制字符串
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="fontPtr"></param>
        /// <param name="startX"></param>
        /// <param name="startY"></param>
        /// <param name="text"></param>
        public static void DrawString(this IntPtr hdc, IntPtr fontPtr, int startX, int startY, uint fontColor, string text)
        {
            IntPtr hOldFont = Gdi32.SelectObject(hdc, fontPtr);
            Gdi32.SetBkMode(hdc, 1);
            Gdi32.SetTextColor(hdc, fontColor);
            int charCount = Encoding.Unicode.GetByteCount(text);
            Gdi32.TextOut(hdc, startX, startY, text, charCount);
            Gdi32.SelectObject(hdc, hOldFont);
        }

        /// <summary>
        /// 以指定画笔填充圆
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="hPen"></param>
        /// <param name="hBrush"></param>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        /// <param name="radius"></param>
        public static void FillEllipse(this IntPtr hdc, IntPtr hPen, IntPtr hBrush, int centerX, int centerY, int radius)
        {
            IntPtr oldPen = Gdi32.SelectObject(hdc, hPen);
            IntPtr oldBrush = Gdi32.SelectObject(hdc, hBrush);
            Gdi32.Ellipse(hdc, centerX - radius, centerY - radius, centerX + radius, centerY + radius);
            Gdi32.SelectObject(hdc, oldPen);
            Gdi32.SelectObject(hdc, oldBrush);
        }

        /// <summary>
        /// 以指定颜色填充圆
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        /// <param name="radius"></param>
        /// <param name="color"></param>
        public static void FillEllipse(this IntPtr hdc, int centerX, int centerY, int radius, uint penColor, uint brushcolor)
        {
            IntPtr hPen = Gdi32.CreatePen(0, 1, penColor);
            IntPtr hBrush = Gdi32.CreateSolidBrush(brushcolor);
            Gdi32.SetBkMode(hdc, 2);
            FillEllipse(hdc, hPen, hBrush, centerX, centerY, radius);
            Gdi32.DeleteObject(hPen);
            Gdi32.DeleteObject(hBrush);
        }

        /// <summary>
        /// 以渐变色填充矩形
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="right"></param>
        /// <param name="bottom"></param>
        /// <param name="startColor"></param>
        /// <param name="endColor"></param>
        public static void FillGradientRectangle(this IntPtr hdc, int left, int top, int right, int bottom, uint startColor, uint endColor)
        {
            vertices[0] = new _TRIVERTEX { X = left, Y = top, Red = (startColor & 0xFF0000) >> 16, Green = (startColor & 0x00FF00) >> 8, Blue = startColor & 0x0000FF, Alpha = 0xFF };
            vertices[1] = new _TRIVERTEX { X = right, Y = bottom, Red = (endColor & 0xFF0000) >> 16, Green = (endColor & 0x00FF00) >> 8, Blue = endColor & 0x0000FF, Alpha = 0xFF };

            mesh[0] = new _GRADIENT_RECT { UpperLeft = 0, LowerRight = 1 };
            MsImg32.GradientFill(hdc, vertices, vertices.Length, mesh, mesh.Length, 0);
        }

        /// <summary>
        /// 以指定画刷填充矩形
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="brush"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public static void FillRectangle(this IntPtr hdc, IntPtr brush, int x, int y, int width, int height)
        {
            tagRECT rect = Win32Graphics.CreateRect(x, y, width, height);
            User32.FillRect(hdc, ref rect, brush);
            Gdi32.DeleteObject(brush);
        }

        /// <summary>
        /// 以指定颜色填充矩形
        /// </summary>
        /// <param name="hdc"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <param name="right"></param>
        /// <param name="bottom"></param>
        /// <param name="color"></param>
        public static void FillRectangle(this IntPtr hdc, int left, int top, int right, int bottom, uint color)
        {
            IntPtr brush = Gdi32.CreateSolidBrush(color);
            FillRectangle(hdc, brush, left, top, right, bottom);
            Gdi32.DeleteObject(brush);
        }
    }
}